import math
import PySide6
from PySide6 import QtCore
from PySide6.QtGui import Qt, QPen, QPixmap, QPainter, QTransform
from PySide6.QtWidgets import QGraphicsRectItem, QGraphicsItem
from PySide6.QtCore import QRectF, QPointF, QSize, QObject

from item.item_type import itemType
from item.close_ctrl_item import CloseCtrlItem
from item.scale_ctrl_item import ScaleCtrlItem
from item.rotate_ctrl_item import RotateCtrlItem

'''
矩形图形项，继承QObject主要是为了使用信号和槽
'''
class RectItem(QGraphicsItem, QObject):

    def __init__(self, parent = None):
        QGraphicsItem.__init__(self, parent)
        QObject.__init__(self, None)
        ctrlItemRadius = 8    # 控制点的半径
        self.__size = QSize(50 + 2 * ctrlItemRadius, 50 + 2 * ctrlItemRadius)  #图形项的大小
        self.MinSie = QSize(1, 1) # 图形项的最小尺寸(注意不要设置为0)
        self.__lastSize = None    # 图形项缩放前的尺寸
        self.__bgImage = QPixmap("./image/desk.png")   #图形项的背景图

        self.__closeItem = CloseCtrlItem(ctrlItemRadius, self)   # 负责控制关闭
        self.__scaleItem = ScaleCtrlItem(ctrlItemRadius, self)   # 负责控制缩放
        self.__rotateItem = RotateCtrlItem(ctrlItemRadius, self) # 负责旋转
        self.__curRotate = 0.0    # 图形项当前的旋转角度
        self.TYPE = itemType.RECTANGLE
        
        self.setFlag(QGraphicsItem.ItemIsFocusable)   # 让图形项可获取焦点
        


    ''' 重写 boundingRect 函数'''
    def boundingRect(self) -> PySide6.QtCore.QRectF:
        # centerPoint = QPointF(0, 0),使用图形项坐标系
        margin = 2   # 裕量，上下左右四个边界都留出一些裕量，方便绘制图形(特别是轮廓)
        return QRectF(0 - self.__size.width() / 2.0 - margin, 0 - self.__size.height() / 2.0 - margin, 
                      self.__size.width() + 2 * margin, self.__size.height() + 2 * margin)

    '''重写 paint 函数'''
    def paint(self, painter: PySide6.QtGui.QPainter, option: PySide6.QtWidgets.QStyleOptionGraphicsItem, widget) -> None:
        # 图形项获得焦点时才显示轮廓
        if self.hasFocus() or self.__closeItem.hasFocus() \
           or self.__scaleItem.hasFocus() or self.__rotateItem.hasFocus():
            pen = QPen()
            pen.setWidth(1)
            pen.setColor(Qt.red)
            pen.setStyle(Qt.DashLine)  # 虚线
            painter.setPen(pen)
            painter.drawRoundedRect( self.rect(), 10, 10)# 绘制轮廓
            self.__closeItem.show()   # 显示控制点
            self.__scaleItem.show()
            self.__rotateItem.show()
        else :   # 隐藏控制点
            self.__closeItem.hide()   
            self.__scaleItem.hide()
            self.__rotateItem.hide()

        # 设置 控制图形项 的位置
        self.__closeItem.setPos( self.rect().topRight() )
        self.__scaleItem.setPos( self.rect().bottomRight() )
        self.__rotateItem.setPos( self.rect().bottomLeft() )
        # 图形项的宽高太小的话，就不显示背景图片了
        if(abs(self.__size.width()) > 40 and abs(self.__size.height()) > 40) :
            spacing = 10  # 背景图和轮廓之间流出一些间距
            painter.drawPixmap(self.rect().x() + spacing, self.rect().y() + spacing, 
                               self.rect().width() - 2 * spacing, 
                               self.rect().height() - 2 * spacing, self.__bgImage)

    '''获取图形项的大小'''
    def size(self)->QSize:
        return self.__size

    '''修改图形项大小'''
    def resize(self, w, h) -> None:
        if(w < self.MinSie.width()) :
            w = self.MinSie.width()

        if h < self.MinSie.height() :
            h = self.MinSie.height()

        self.__size = QSize(w, h)
        self.update()

    '''获取图形项矩形框（图形项的边界）'''
    def rect(self)->QRectF:
        return QRectF(0 - self.__size.width() / 2, 0 - self.__size.height() / 2.0 , 
                      self.__size.width() , self.__size.height() )

    '''
    缩放图形项槽函数。原理如下， 二维坐标下向量围绕原点的逆时针旋转角度B的公式： 
    x1 = x0 * cosB + y0 * sinB
    y1 = -x0 * sinB + y0 * cosB
    顺时针旋转就把角度变为负
    参考：向量旋转公式(https://blog.csdn.net/zhinanpolang/article/details/82912325)
    '''
    @QtCore.Slot(QRectF, bool)
    def scaleItemSlot(self, moveRect, isFinish):
        if isFinish == True:
            self.__lastSize = None
            return
        else :
            if self.__lastSize == None :   # 在缩放控制点刚被按下时，记录一下此时图形项的size
                self.__lastSize = self.size()

        delta = moveRect.bottomRight() - self.pos()   # 计算图形项中心点和moveRect.bottomRight()两点组成的向量
        # 我们计算的是水平情况下图形项的缩放比例，所以加个符号，表示把图形项旋转回去，变为水平状态
        Radian = -self.__curRotate * (math.pi / 180)  # 把角度制改为弧度制
        deltaTransX = delta.x() * math.cos(Radian ) - delta.y() * math.sin(Radian)  
        deltaTransY = delta.x() * math.sin(Radian) + delta.y() * math.cos(Radian) 
        xScale = deltaTransX / (self.__lastSize.width() / 2)
        yScale = deltaTransY / (self.__lastSize.height() / 2)
        self.resize(self.__lastSize.width() * xScale, self.__lastSize.height() * yScale)
    
    '''缩放图形项槽函数'''
    @QtCore.Slot(float, bool)
    def rotateItemSlot(self, angle, isFinish):
        transform = QTransform()
        transform.rotate(self.__curRotate + angle)
        self.setTransform(transform)
        if isFinish == True:
            self.__curRotate += angle
            self.__curRotate %= 360
            # print(self.__curRotate)
        